package com.scilvet.reportcomposer;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.InputStream;
import java.util.Date;
import java.util.GregorianCalendar;

import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.log4j.Logger;

import com.scilvet.reportcomposer.account.AccountStore;
import com.scilvet.reportcomposer.data.CSVDataReader;
import com.scilvet.reportcomposer.data.CSVReportWriter;
import com.scilvet.reportcomposer.data.DataReader;
import com.scilvet.reportcomposer.data.ReportWriter;
import com.scilvet.reportcomposer.exception.FileException;
import com.scilvet.reportcomposer.node.AccountNode;
import com.scilvet.reportcomposer.report.FileReportFactory;
import com.scilvet.reportcomposer.report.Report;
import com.scilvet.reportcomposer.report.ReportFactory;
import com.scilvet.reportcomposer.report.ReportStore;
import com.scilvet.reportcomposer.ui.SwingUserInterface;
import com.scilvet.reportcomposer.ui.UserInterface;

public class ReportComposer {
	
	private static ConfigurationManager configurationManager = null;
	private static UserInterface userInterface = null;
	
	private static ReportFactory<InputStream> reportFactory = null;
	
	private static Logger logger = Logger.getLogger(ReportComposer.class);

	public static void main(String[] args) {
		
		logger.info("Application started");
		
		try {
			configurationManager = new ConfigurationManager();
		} catch (FileException e) {
			error("Error loading configuration", e);
		}
		
		ReportComposer reportComposer = new ReportComposer();
		userInterface = new SwingUserInterface(reportComposer);
		reportFactory = new FileReportFactory();
		
		userInterface.showMain();
	}
	
	public static void error(String message, Throwable e) {
		logger.error(message);
		logger.error(e.getMessage());
		userInterface.showErrorNotification(message + ": " + e.getMessage());
	}
	
	public void fatalError(String message) {
		logger.fatal(message);
		userInterface.showErrorNotification("Fatal error: " + message);
		System.exit(-1);
	}
	
	public String[] getAvailableReports() {
		
		String reportDirectoryString = configurationManager.getProperty(ConfigurationManager.REPORT_DIRECTORY);
		File reportDirectory = new File(reportDirectoryString);
		if (!reportDirectory.isDirectory() || !reportDirectory.exists()) {
			fatalError("Report location " + reportDirectoryString + " is not a valid directory resource.");
		}
		
		return reportDirectory.list(new FilenameFilter() {
			
			@Override
			public boolean accept(File file, String name) {
				return name.endsWith(".rpt");
			}
		});
	}
	
	public void computeReport(String reportFilename, File accountFile) {
		ReportStore reportManager = null;
		DataReader dataReader = null;
		ReportWriter reportWriter = null;
		AccountStore accountStore = null;
				
		String reportDirectoryString = configurationManager.getProperty(ConfigurationManager.REPORT_DIRECTORY);
		
		File reportFile = new File(reportDirectoryString + reportFilename);
		try {
			reportManager = reportFactory.getReport(new FileInputStream(reportFile));
		} catch (FileNotFoundException e) {
			error("Report file " + reportFile.getAbsolutePath() + " not found", e);
		} catch (Exception e) {
			error("Error loading report description " + reportFile.getName(), e);
		} catch (Error e) {
			error("Error loading report description " + reportFile.getName(), e);
		}
		
		dataReader = new CSVDataReader();
		
		try {
			accountStore = dataReader.loadData(accountFile);
		} catch (FileException e) {
			error("Error loading accound data " + accountFile.getName() + ": ", e);
		}
		
		AccountNode.setAccountStore(accountStore);
		String outputDirectory = configurationManager.getProperty(ConfigurationManager.OUTPUT_DIRECTORY);
		
		for (Report report : reportManager) {
			File outputFile = new File(outputDirectory + report.getName() + "_" + getDate() + CSVReportWriter.EXTENSION);
			reportWriter = new CSVReportWriter();
			try {
				reportWriter.writeReport(report, outputFile);
			} catch (FileException e) {
				error("Error writing output report " + reportFile.getName(), e);
			}
		}
	}
	
	private String getDate() {
		
		Date now = GregorianCalendar.getInstance().getTime();
		return DateFormatUtils.format(now, "yyyy-MM-dd_HH-mm-ss");
	}
}
